home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / editor / j414src.arc / RECOVER.C < prev    next >
C/C++ Source or Header  |  1989-10-10  |  19KB  |  851 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* Recovers JOVE files after a system/editor crash.
  9.    Usage: recover [-d directory] [-syscrash]
  10.    The -syscrash option is specified in /etc/rc and what it does it
  11.    move all the jove tmp files from TMP_DIR (/tmp) to REC_DIR (/usr/preserve).
  12.    recover -syscrash must be invoked in /ect/rc BEFORE /tmp gets cleared out.
  13.    (about the same place as expreserve gets invoked to save ed/vi/ex files.
  14.  
  15.    The -d option lets you specify the directory to search for tmp files when
  16.    the default isn't the right one.
  17.  
  18.    Look in Makefile to change the default directories. */
  19.  
  20. #include <stdio.h>    /* Do stdio first so it doesn't override OUR
  21.                definitions. */
  22. #include "jove.h"
  23. #include "temp.h"
  24. #include "rec.h"
  25. #include "rectune.h"
  26. #include <signal.h>
  27. #include <sys/file.h>
  28. #include <sys/stat.h>
  29. #include <sys/dir.h>
  30. #include <pwd.h>
  31. #include <time.h>
  32. #ifdef SYSV
  33. # include <sys/utsname.h>
  34. #endif
  35.  
  36. #ifndef L_SET
  37. #    define L_SET    0
  38. #    define L_INCR    1
  39. #endif
  40.  
  41. extern char    *ctime proto((const time_t *));
  42.  
  43. private char    blk_buf[JBUFSIZ];
  44. private int    nleft;
  45. private FILE    *ptrs_fp;
  46. private int    data_fd;
  47. private struct rec_head    Header;
  48. private long    Nchars,
  49.     Nlines;
  50. private char    tty[] = "/dev/tty";
  51. private int    UserID,
  52.     Verbose = 0;
  53. private char    *Directory = 0;        /* the directory we're looking in */
  54.  
  55. private struct file_pair {
  56.     char    *file_data,
  57.         *file_rec;
  58. #define INSPECTED    01
  59.     int    file_flags;
  60.     struct file_pair    *file_next;
  61. } *First = 0;
  62.  
  63. private struct rec_entry    *buflist[100];    /* system initializes to 0 */
  64.  
  65. #ifndef BSD_DIR
  66.  
  67. typedef struct {
  68.     int    d_fd;        /* File descriptor for this directory */
  69. } DIR;
  70.  
  71. DIR *
  72. opendir(dir)
  73. char    *dir;
  74. {
  75.     DIR    *dp = (DIR *) malloc(sizeof *dp);
  76.  
  77.     if ((dp->d_fd = open(dir, 0)) == -1)
  78.         return NULL;
  79.     return dp;
  80. }
  81.  
  82. closedir(dp)
  83. DIR    *dp;
  84. {
  85.     (void) close(dp->d_fd);
  86.     free(dp);
  87. }
  88.  
  89. struct direct *
  90. readdir(dp)
  91. DIR    *dp;
  92. {
  93.     static struct direct    dir;
  94.  
  95.     do
  96.         if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
  97.             return NULL;
  98. #if defined(elxsi) && defined(SYSV)
  99.     /*
  100.      * Elxsi has a BSD4.2 implementation which may or may not use
  101.      * `twisted inodes' ...  Anyone able to check?
  102.      */
  103.     while (*(unsigned short *)&dir.d_ino == 0);
  104. #else
  105.     while (dir.d_ino == 0);
  106. #endif
  107.  
  108.     return &dir;
  109. }
  110.  
  111. #endif /* BSD4_2 */
  112.  
  113. /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
  114.    long. */
  115.  
  116. private char    *getblock proto((daddr atl));
  117.  
  118. void
  119. getline(tl, buf)
  120. daddr    tl;
  121. char    *buf;
  122. {
  123.     register char    *bp,
  124.             *lp;
  125.     register int    nl;
  126.  
  127.     lp = buf;
  128.     bp = getblock(tl >> 1);
  129.     nl = nleft;
  130.     tl = blk_round(tl);
  131.  
  132.     while ((*lp++ = *bp++) != '\0') {
  133.         if (--nl == 0) {
  134.             tl = forward_block(tl);
  135.             bp = getblock(tl >> 1);
  136.             nl = nleft;
  137.         }
  138.     }
  139. }
  140.  
  141. private char *
  142. getblock(atl)
  143. daddr    atl;
  144. {
  145.     int    bno,
  146.         off;
  147.     static int    curblock = -1;
  148.  
  149.     bno = da_to_bno(atl);
  150.     off = da_to_off(atl);
  151.     nleft = JBUFSIZ - off;
  152.  
  153.     if (bno != curblock) {
  154.         extern long    lseek proto((int, long, int));
  155.  
  156.         lseek(data_fd, (long) bno * JBUFSIZ, L_SET);
  157.         read(data_fd, blk_buf, (size_t)JBUFSIZ);
  158.         curblock = bno;
  159.     }
  160.     return blk_buf + off;
  161. }
  162.  
  163. char *
  164. copystr(s)
  165. char    *s;
  166. {
  167.     char    *str;
  168.  
  169.     str = malloc((size_t) (strlen(s) + 1));
  170.     strcpy(str, s);
  171.  
  172.     return str;
  173. }
  174.  
  175. /* Scandir returns the number of entries or -1 if the directory cannoot
  176.    be opened or malloc fails. */
  177.  
  178. private int
  179. scandir(dir, nmptr, qualify, sorter)
  180. char    *dir;
  181. struct direct    ***nmptr;
  182. int    (*qualify) proto((struct direct *));
  183. int    (*sorter) proto((UnivConstPtr, UnivConstPtr));
  184. {
  185.     DIR    *dirp;
  186.     struct direct    *entry,
  187.             **ourarray;
  188.     int    nalloc = 10,
  189.         nentries = 0;
  190.  
  191.     if ((dirp = opendir(dir)) == NULL)
  192.         return -1;
  193.     ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
  194.     while ((entry = readdir(dirp)) != NULL) {
  195.         if (qualify != NULL && (*qualify)(entry) == 0)
  196.             continue;
  197.         if (nentries == nalloc) {
  198.             ourarray = (struct direct **) realloc((char *)ourarray,
  199.                 (nalloc += 10) * sizeof (struct direct));
  200.             if (ourarray == NULL)
  201.                 return -1;
  202.         }
  203.         ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
  204.         *ourarray[nentries] = *entry;
  205.         nentries += 1;
  206.     }
  207.     closedir(dirp);
  208.     if (nentries != nalloc)
  209.         ourarray = (struct direct **) realloc((char *)ourarray,
  210.                     (nentries * sizeof (struct direct)));
  211.     if (sorter != NULL)
  212.         qsort((UnivPtr)ourarray, (size_t) nentries, sizeof (struct direct **), sorter);
  213.     *nmptr = ourarray;
  214.  
  215.     return nentries;
  216. }
  217.  
  218. private char    *CurDir;
  219.  
  220. /* Scan the DIRNAME directory for jove tmp files, and make a linked list
  221.    out of them. */
  222.  
  223. private int    add_name proto((struct direct *dp));
  224.  
  225. private void
  226. get_files(dirname)
  227. char    *dirname;
  228. {
  229.     struct direct    **nmptr;
  230.  
  231.     CurDir = dirname;
  232.     First = NULL;
  233.     scandir(dirname, &nmptr, add_name,
  234.         (int (*) proto((UnivConstPtr, UnivConstPtr)))NULL);
  235. }
  236.  
  237. private int
  238. add_name(dp)
  239. struct direct    *dp;
  240. {
  241.     char    dfile[128],
  242.         rfile[128];
  243.     struct file_pair    *fp;
  244.     struct rec_head        header;
  245.     int    fd;
  246.  
  247.     if (strncmp(dp->d_name, "jrec", (size_t)4) != 0)
  248.         return 0;
  249.     /* If we get here, we found a "recover" tmp file, so now
  250.        we look for the corresponding "data" tmp file.  First,
  251.        though, we check to see whether there is anything in
  252.        the "recover" file.  If it's 0 length, there's no point
  253.        in saving its name. */
  254.     (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
  255.     (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4);
  256.     if ((fd = open(rfile, 0)) != -1) {
  257.         if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
  258.             close(fd);
  259.             return 0;
  260.         } else
  261.             close(fd);
  262.     }
  263.     if (access(dfile, 0) != 0) {
  264.         fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name);
  265.         fprintf(stderr, "so deleting...\n");
  266.         (void) unlink(rfile);
  267.         (void) unlink(dfile);
  268.         return 0;
  269.     }
  270.     /* If we get here, we've found both files, so we put them
  271.        in the list. */
  272.     fp = (struct file_pair *) malloc (sizeof *fp);
  273.     if ((char *) fp == 0) {
  274.         fprintf(stderr, "recover: cannot malloc for file_pair.\n");
  275.         exit(-1);
  276.     }
  277.     fp->file_data = copystr(dfile);
  278.     fp->file_rec = copystr(rfile);
  279.     fp->file_flags = 0;
  280.     fp->file_next = First;
  281.     First = fp;
  282.  
  283.     return 1;
  284. }
  285.  
  286. private void
  287. options()
  288. {
  289.     printf("Options are:\n");
  290.     printf("    ?        list options.\n");
  291.     printf("    get        get a buffer to a file.\n");
  292.     printf("    list        list known buffers.\n");
  293.     printf("    print        print a buffer to terminal.\n");
  294.     printf("    quit        quit and delete jove tmp files.\n");
  295.     printf("    restore        restore all buffers.\n");
  296. }
  297.  
  298. /* Returns a legitimate buffer # */
  299.  
  300. private void    tellme proto((char *, char *)),
  301.     list proto((void));
  302.  
  303. private struct rec_entry **
  304. getsrc()
  305. {
  306.     char    name[128];
  307.     int    number;
  308.  
  309.     for (;;) {
  310.         tellme("Which buffer ('?' for list)? ", name);
  311.         if (name[0] == '?')
  312.             list();
  313.         else if (name[0] == '\0')
  314.             return 0;
  315.         else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
  316.             return &buflist[number];
  317.         else {
  318.             int    i;
  319.  
  320.             for (i = 1; i <= Header.Nbuffers; i++)
  321.                 if (strcmp(buflist[i]->r_bname, name) == 0)
  322.                     return &buflist[i];
  323.             printf("%s: unknown buffer.\n", name);
  324.         }
  325.     }
  326. }
  327.  
  328. /* Get a destination file name. */
  329.  
  330. static char *
  331. getdest()
  332. {
  333.     static char    filebuf[256];
  334.  
  335.     tellme("Output file: ", filebuf);
  336.     if (filebuf[0] == '\0')
  337.         return 0;
  338.     return filebuf;
  339. }
  340.  
  341. #include "ctype.h"
  342.  
  343. private char *
  344. readword(buf)
  345. char    *buf;
  346. {
  347.     int    c;
  348.     char    *bp = buf;
  349.  
  350.     while (strchr(" \t\n", c = getchar()))
  351.         ;
  352.  
  353.     do {
  354.         if (strchr(" \t\n", c))
  355.             break;
  356.         *bp++ = c;
  357.     } while ((c = getchar()) != EOF);
  358.     *bp = 0;
  359.  
  360.     return buf;
  361. }
  362.  
  363. private void
  364. tellme(quest, answer)
  365. char    *quest,
  366.     *answer;
  367. {
  368.     if (stdin->_cnt <= 0) {
  369.         printf("%s", quest);
  370.         fflush(stdout);
  371.     }
  372.     readword(answer);
  373. }
  374.  
  375. /* Print the specified file to standard output. */
  376.  
  377. private jmp_buf    int_env;
  378.  
  379. private SIGRESULT
  380. catch(junk)
  381. int    junk;
  382. {
  383.     longjmp(int_env, 1);
  384.     /*NOTREACHED*/
  385. }
  386.  
  387. private void    get proto((struct rec_entry **src, char *dest));
  388.  
  389. private void
  390. restore()
  391. {
  392.     register int    i;
  393.     char    tofile[100],
  394.         answer[30];
  395.     int    nrecovered = 0;
  396.  
  397.     for (i = 1; i <= Header.Nbuffers; i++) {
  398.         (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
  399. tryagain:
  400.         printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
  401.                              tofile);
  402.         tellme(" ", answer);
  403.         switch (answer[0]) {
  404.         case 'y':
  405.             break;
  406.  
  407.         case 'n':
  408.             continue;
  409.  
  410.         default:
  411.             tellme("What file should I use instead? ", tofile);
  412.             goto tryagain;
  413.         }
  414.         get(&buflist[i], tofile);
  415.         nrecovered += 1;
  416.     }
  417.     printf("Recovered %d buffers.\n", nrecovered);
  418. }
  419.  
  420. private void    dump_file proto((int which, FILE *out));
  421.  
  422. private void
  423. get(src, dest)
  424. struct rec_entry    **src;
  425. char    *dest;
  426. {
  427.     FILE    *outfile;
  428.  
  429.     if (src == 0 || dest == 0)
  430.         return;
  431.     (void) signal(SIGINT, catch);
  432.     if (setjmp(int_env) == 0) {
  433.         if (dest == tty)
  434.             outfile = stdout;
  435.         else {
  436.             if ((outfile = fopen(dest, "w")) == NULL) {
  437.                 printf("recover: cannot create %s.\n", dest);
  438.                 (void) signal(SIGINT, SIG_DFL);
  439.                 return;
  440.             }
  441.             printf("\"%s\"", dest);
  442.         }
  443.         dump_file(src - buflist, outfile);
  444.     } else
  445.         printf("\nAborted!\n");
  446.     (void) signal(SIGINT, SIG_DFL);
  447.     if (dest != tty) {
  448.         fclose(outfile);
  449.         printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
  450.     }
  451. }
  452.  
  453. private char **
  454. scanvec(args, str)
  455. register char    **args,
  456.         *str;
  457. {
  458.     while (*args) {
  459.         if (strcmp(*args, str) == 0)
  460.             return args;
  461.         args += 1;
  462.     }
  463.     return 0;
  464. }
  465.  
  466. private void
  467. read_rec(recptr)
  468. struct rec_entry    *recptr;
  469. {
  470.     if (fread((char *) recptr, sizeof *recptr, (size_t)1, ptrs_fp) != 1)
  471.         fprintf(stderr, "recover: cannot read record.\n");
  472. }
  473.  
  474. private void
  475. seekto(which)
  476. int    which;
  477. {
  478.     long    offset;
  479.     int    i;
  480.  
  481.     offset = sizeof (Header) + (Header.Nbuffers * sizeof (struct rec_entry));
  482.     for (i = 1; i < which; i++)
  483.         offset += buflist[i]->r_nlines * sizeof (daddr);
  484.     fseek(ptrs_fp, offset, L_SET);
  485. }
  486.  
  487. private void
  488. makblist()
  489. {
  490.     int    i;
  491.  
  492.     fseek(ptrs_fp, (long) sizeof (Header), L_SET);
  493.     for (i = 1; i <= Header.Nbuffers; i++) {
  494.         if (buflist[i] == 0)
  495.             buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
  496.         read_rec(buflist[i]);
  497.     }
  498.     while (buflist[i]) {
  499.         free((char *) buflist[i]);
  500.         buflist[i] = 0;
  501.         i += 1;
  502.     }
  503. }
  504.  
  505. private daddr
  506. getaddr(fp)
  507. register FILE    *fp;
  508. {
  509.     register int    nchars = sizeof (daddr);
  510.     daddr    addr;
  511.     register char    *cp = (char *) &addr;
  512.  
  513.     while (--nchars >= 0)
  514.         *cp++ = getc(fp);
  515.  
  516.     return addr;
  517. }
  518.  
  519. private void
  520. dump_file(which, out)
  521. int    which;
  522. FILE    *out;
  523. {
  524.     register int    nlines;
  525.     register daddr    addr;
  526.     char    buf[JBUFSIZ];
  527.  
  528.     seekto(which);
  529.     nlines = buflist[which]->r_nlines;
  530.     Nchars = Nlines = 0L;
  531.     while (--nlines >= 0) {
  532.         addr = getaddr(ptrs_fp);
  533.         getline(addr, buf);
  534.         Nlines += 1;
  535.         Nchars += 1 + strlen(buf);
  536.         fputs(buf, out);
  537.         if (nlines > 0)
  538.             fputc('\n', out);
  539.     }
  540. }
  541.  
  542. /* List all the buffers. */
  543.  
  544. private void
  545. list()
  546. {
  547.     int    i;
  548.  
  549.     for (i = 1; i <= Header.Nbuffers; i++)
  550.         printf("%d) buffer %s  \"%s\" (%d lines)\n", i,
  551.             buflist[i]->r_bname,
  552.             buflist[i]->r_fname,
  553.             buflist[i]->r_nlines);
  554. }
  555.  
  556. private void    ask_del proto((char *prompt, struct file_pair *fp));
  557.  
  558. private int
  559. doit(fp)
  560. struct file_pair    *fp;
  561. {
  562.     char    answer[30];
  563.     char    *datafile = fp->file_data,
  564.         *pntrfile = fp->file_rec;
  565.  
  566.     ptrs_fp = fopen(pntrfile, "r");
  567.     if (ptrs_fp == NULL) {
  568.         if (Verbose)
  569.             fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
  570.         return 0;
  571.     }
  572.     fread((char *) &Header, sizeof Header, (size_t)1, ptrs_fp);
  573.     if (Header.Uid != UserID)
  574.         return 0;
  575.  
  576.     /* Don't ask about JOVE's that are still running ... */
  577. #ifdef KILL0
  578.     if (kill(Header.Pid, 0) == 0)
  579.         return 0;
  580. #endif /* KILL0 */
  581.  
  582.     if (Header.Nbuffers == 0) {
  583.         printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
  584.         ask_del(" ", fp);
  585.         return 1;
  586.     }
  587.  
  588.     if (Header.Nbuffers < 0) {
  589.         fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
  590.         ask_del("Should I delete it? ", fp);
  591.         return 1;    /* We'll, we sort of found something. */
  592.     }
  593.     printf("Found %d buffer%s last updated: %s",
  594.         Header.Nbuffers,
  595.         Header.Nbuffers != 1 ? "s" : "",
  596.         ctime(&Header.UpdTime));
  597.     data_fd = open(datafile, 0);
  598.     if (data_fd == -1) {
  599.         fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
  600.         ask_del("Should I delete the tmp files? ", fp);
  601.         return 1;
  602.     }
  603.     makblist();
  604.     list();
  605.  
  606.     for (;;) {
  607.         tellme("(Type '?' for options): ", answer);
  608.         switch (answer[0]) {
  609.         case '\0':
  610.             continue;
  611.  
  612.         case '?':
  613.             options();
  614.             break;
  615.  
  616.         case 'l':
  617.             list();
  618.             break;
  619.  
  620.         case 'p':
  621.             get(getsrc(), tty);
  622.             break;
  623.  
  624.         case 'q':
  625.             ask_del("Shall I delete the tmp files? ", fp);
  626.             return 1;
  627.  
  628.         case 'g':
  629.             {    /* So it asks for src first. */
  630.             char    *dest;
  631.             struct rec_entry    **src;
  632.  
  633.             if ((src = getsrc()) == 0)
  634.                 break;
  635.             dest = getdest();
  636.             get(src, dest);
  637.             break;
  638.             }
  639.  
  640.         case 'r':
  641.             restore();
  642.             break;
  643.  
  644.         default:
  645.             printf("I don't know how to \"%s\"!\n", answer);
  646.             break;
  647.         }
  648.     }
  649. }
  650.  
  651. private void    del_files proto((struct file_pair *fp));
  652.  
  653. private void
  654. ask_del(prompt, fp)
  655. char    *prompt;
  656. struct file_pair    *fp;
  657. {
  658.     char    yorn[20];
  659.  
  660.     tellme(prompt, yorn);
  661.     if (yorn[0] == 'y')
  662.         del_files(fp);
  663. }
  664.  
  665. private void
  666. del_files(fp)
  667. struct file_pair    *fp;
  668. {
  669.     (void) unlink(fp->file_data);
  670.     (void) unlink(fp->file_rec);
  671. }
  672.  
  673.  
  674.  
  675. MailUser(rec)
  676. struct rec_head *rec;
  677. {
  678. #ifdef SYSV
  679.     struct utsname mach;
  680. #else
  681.     char mach[BUFSIZ];
  682. #endif
  683.     char mail_cmd[BUFSIZ];
  684.     char *last_update;
  685.     char *buf_string;
  686.     FILE *mail_pipe;
  687.     struct passwd *pw;
  688.     extern struct passwd *getpwuid proto((int));
  689.  
  690.     if ((pw = getpwuid(rec->Uid))== NULL)
  691.         return;
  692. #ifdef SYSV
  693.     if (uname(&mach) < 0)
  694.         strcpy(mach.sysname, "unknown");
  695. #else
  696.     gethostname(mach, sizeof(mach));
  697. #endif
  698.     last_update = ctime(&(rec->UpdTime));
  699.     /* Start up mail */
  700.     sprintf(mail_cmd, "/bin/mail %s", pw->pw_name);
  701.     setuid(getuid());
  702.     if ((mail_pipe = popen(mail_cmd, "w")) == NULL)
  703.         return;
  704.     setbuf(mail_pipe, mail_cmd);
  705.     /* Let's be grammatically correct! */
  706.     if (rec->Nbuffers == 1)
  707.         buf_string = "buffer";
  708.     else
  709.         buf_string = "buffers";
  710.     fprintf(mail_pipe, "Subject: System crash\n");
  711.     fprintf(mail_pipe, " \n");
  712.     fprintf(mail_pipe, "Jove saved %d %s when the system \"%s\"\n",
  713.      rec->Nbuffers, buf_string,
  714. #ifdef SYSV
  715.      mach.sysname
  716. #else
  717.      mach
  718. #endif
  719.      );
  720.     fprintf(mail_pipe, "crashed on %s\n\n", last_update);
  721.     fprintf(mail_pipe, "You can retrieve the %s using Jove's -r\n", 
  722.      buf_string);
  723.     fprintf(mail_pipe, "(recover option) i.e. give the command.\n");
  724.     fprintf(mail_pipe, "\tjove -r\n");
  725.     fprintf(mail_pipe, "See the Jove manual for more details\n");
  726.     pclose(mail_pipe);
  727. }
  728.  
  729.  
  730. savetmps()
  731. {
  732.     struct file_pair    *fp;
  733.     int    status,
  734.         pid,
  735.         fd;
  736.     struct rec_head        header;
  737.     char    buf[BUFSIZ];
  738.     char    *fname;
  739.     struct stat        stbuf;
  740.  
  741.     if (strcmp(TMP_DIR, REC_DIR) == 0)
  742.         return;        /* Files are moved to the same place. */
  743.     get_files(TMP_DIR);
  744.     for (fp = First; fp != 0; fp = fp->file_next) {
  745.         stat(fp->file_data, &stbuf);
  746.         switch (pid = fork()) {
  747.         case -1:
  748.             fprintf(stderr, "recover: can't fork\n!");
  749.             exit(-1);
  750.  
  751.         case 0:
  752.             fprintf(stderr, "Recovering: %s, %s\n", fp->file_data,
  753.              fp->file_rec);
  754.             if ((fd = open(fp->file_rec, 0)) != -1) {
  755.                 if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
  756.                     close(fd);
  757.                         return 0;
  758.                 } else
  759.                     close(fd);
  760.             }
  761.             MailUser(&header);
  762.             execl("/bin/mv", "mv", fp->file_data, fp->file_rec, 
  763.                   REC_DIR, (char *)0);
  764.             fprintf(stderr, "recover: cannot execl /bin/mv.\n");
  765.             exit(-1);
  766.  
  767.         default:
  768.             while (wait(&status) != pid)
  769.                 ;
  770.             if (status != 0)
  771.                 fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
  772.             fname = fp->file_data + strlen(TMP_DIR);
  773.             strcpy(buf, REC_DIR);
  774.             strcat(buf, fname);
  775.             if(chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0)
  776.                 perror("recover: chown failed.");
  777.             fname = fp->file_rec + strlen(TMP_DIR);
  778.             strcpy(buf, REC_DIR);
  779.             strcat(buf, fname);
  780.             if(chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0)
  781.                 perror("recover: chown failed.");
  782.         }
  783.     }
  784. }
  785.  
  786. private int
  787. lookup(dir)
  788. char    *dir;
  789. {
  790.     struct file_pair    *fp;
  791.     int    nfound = 0;
  792.  
  793.     printf("Checking %s ...\n", dir);
  794.     Directory = dir;
  795.     get_files(dir);
  796.     for (fp = First; fp != 0; fp = fp->file_next) {
  797.         nfound += doit(fp);
  798.         if (ptrs_fp)
  799.             (void) fclose(ptrs_fp);
  800.         if (data_fd > 0)
  801.             (void) close(data_fd);
  802.     }
  803.     return nfound;
  804. }
  805.  
  806. void
  807. main(argc, argv)
  808. int    argc;
  809. char    *argv[];
  810. {
  811.     int    nfound;
  812.     char    **argvp;
  813.     char    *tmp_dir;
  814.  
  815.     UserID = getuid();
  816.  
  817.     if (scanvec(argv, "-help")) {
  818.         printf("recover: usage: recover [-d directory] [-syscrash]\n");
  819.         printf("Use \"jove -r\" after JOVE has died for some\n");
  820.         printf("unknown reason.\n\n");
  821.         printf("Use \"%s -syscrash\"\n", Recover);
  822.          printf("when the system is in the process of rebooting.");
  823.         printf("This is done automatically at reboot time\n");
  824.         printf("and so most of you don't have to worry about that.\n\n");
  825.         printf("Use \"recover -d directory\" when the tmp files are store\n");
  826.         printf("in DIRECTORY instead of the default one (/tmp).\n");
  827.         exit(0);
  828.     }
  829.     if (scanvec(argv, "-v"))
  830.         Verbose = YES;
  831.     if (scanvec(argv, "-syscrash")) {
  832.         printf("Recovering jove files ... ");
  833.         savetmps();
  834.         printf("Done.\n");
  835.         exit(0);
  836.     }
  837.     if ((argvp = scanvec(argv, "-uid")) != NULL)
  838.         UserID = atoi(argvp[1]);
  839.     if ((argvp = scanvec(argv, "-d")) != NULL)
  840.         tmp_dir = argvp[1];
  841.     else
  842.         tmp_dir = TmpFilePath;
  843.     /* Check default directory */
  844.     nfound = lookup(tmp_dir);
  845.     /* Check whether anything was saved when system died? */
  846.     if (strcmp(tmp_dir, REC_DIR) != 0)
  847.         nfound += lookup(REC_DIR);
  848.     if (nfound == 0)
  849.         printf("There's nothing to recover.\n");
  850. }
  851.